home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1999 July / Macworld (1999-07).dmg / Shareware World / Info / For Developers / Mops 3.4.sea / Mops source / PPC source / setup < prev    next >
Text File  |  1999-02-05  |  28KB  |  1,109 lines

  1. (*
  2. This is the first file compiled in the PPC Mops image.  CROSS (in cg6)
  3. switches 68k Mops to generating PPC code.
  4.  
  5. At the beginning of the code area, there's an info block with certain
  6. quantities we need to set everything up.  Here's the format - note that
  7. this MUST AGREE with what we have in cg4/zPEF!
  8.  
  9. ent pt offset      length        what it is
  10.  
  11.     0            4 bytes        initial branch
  12.     4            4 bytes        code size
  13.     8            4 bytes        data size
  14.     12            4 bytes        displacement from code_start to nuc_code_start
  15.                                 (i.e. code generator code area)
  16.     16            4 bytes        displacement from data_start to nuc_data_start
  17.                                 (i.e. code generator data area)
  18.     20            32 bytes    initial CONTEXT
  19.     52             4 bytes    flags
  20.     56             4 bytes    #bytes chopped from bottom of seg 8
  21.     60             4 bytes    #bytes chopped from bottom of seg 9
  22.     64             4 bytes    total code size (including spare room)
  23.     68             4 bytes    total data size (including spare room)
  24.     72             8 bytes    spare
  25.  
  26.         total: 80 bytes.
  27. *)
  28.  
  29. cross
  30.  
  31. marker m__setup        \ also marks the start of the PPC dic
  32.  
  33. : NULL  ;
  34.  
  35. \    ================== REGISTER DEFINITIONS  ===================
  36.  
  37. \ r0 is scratch
  38.  
  39. 0    constant    false
  40. -1    constant    true
  41.  
  42. 1    constant    sys_SP_reg
  43. 2    constant    RTOC_reg
  44. 10    constant    rZ_reg
  45. 11    constant    rX_reg
  46. 12    constant    rY_reg
  47. 13    constant    mainCode_reg
  48. 14    constant    mainData_reg
  49. 15    constant    modCode_reg
  50. 16    constant    modData_reg
  51. 17    constant    RP_reg
  52. 18    constant    SP_reg
  53. 19    constant    FSP_reg
  54. 20    constant    obj_base_reg
  55. 21    constant    I_reg            \ can be used for a local if no DO...LOOP
  56.                                 \  or FOR...NEXT
  57. 22    constant    do_limit_reg    \ can be used for a local if no DO..LOOP
  58.  
  59. 21    constant    1st_gpr_local
  60. 14    constant    1st_fpr_local
  61.  
  62.  
  63. \ Now we define some constants, values etc. which we need at setup time.
  64. \ Most of the others are defined near the start of pnuc1.
  65.  
  66. 800  cells    constant    RSTACK_SIZE
  67. 1000 cells    constant    STACK_SIZE
  68. 200 3 <<    constant    FSTACK_SIZE
  69. 4            constant    1CELL
  70. $ 7FFFFFFF    constant    BIG#
  71. 65520        constant    DISPL_RANGE        \ what we can fit in a signed 16-bits
  72.                                         \  displacement, rounded down to
  73.                                         \  8-byte alignment
  74. 32760        constant    HALF_DISPL_RANGE
  75.  
  76. $ FFFF8103    constant    nilP
  77. $ FFFF8101    constant    nilH
  78.  
  79. $ 7FF01000    constant    quietNAN    \ NAN(128) (quiet)
  80.  
  81. 204            constant    FCBlen
  82. 30            constant    HOLDlen
  83. 200            constant    PADlen
  84. 400            constant    TIBlen
  85. 512            constant    ErrDumpLen
  86.  
  87. true        constant    PPC?        \ ALWAYS true from CROSS onwards, by definition!
  88.  
  89.  
  90. ErrDumpLen  8 / 5 -
  91.             constant    maxDump
  92.  
  93. FCBlen HOLDlen + PADlen + TIBlen + ErrDumpLen + 8 +
  94.             constant    FBlkLen        \ the extra 8 is for the object header
  95.  
  96.  
  97. entry_point_toc_offset
  98.             constant    entry_point_TOC_offset
  99.  
  100.  
  101. \        ==================================
  102.  
  103. $ 33333333    value        dd        \ marker for start of data area,
  104.                                 \  straight after TOC
  105.  
  106. $ 100000    value        SPARE_CODE_SIZE
  107. $ 10000        value        SPARE_DATA_SIZE
  108.  
  109. ' null        vect        OBJINIT            \ initializes Mops objects
  110.  
  111. 0            value        CDP
  112. 0            value        DP
  113. 0            value        mod_seg#        \ code seg# of currently running module, or 0
  114. 0            value        comp_seg#        \ code seg# of module being compiled, or 0
  115. 0            value        last_RP_seg#    \ seg# of last reloc pointer processed by @abs
  116.  
  117. 0            value        prev_CDP        \ used in finding range for fix_caches
  118.  
  119. 0            value        PAD
  120. 0            value        TIB
  121. 0            value        ^errDump
  122. 0            value        theRgn
  123. 0            value        SP0
  124. 0            value        RP0
  125. 0            value        FSP0
  126. 0            value        CONTEXT
  127.  
  128. false        value        instld?
  129. true        value        fWind?
  130. false        value        EMIT?
  131.  
  132. 0            value        code_start
  133. 0            value        nuc_code_start
  134. 0            value        code_limit
  135.  
  136. 0            value        data_start
  137. 0            value        nuc_data_start
  138. 0            value        data_limit
  139.  
  140. 0            value        SYSTEM_ERR#
  141.  
  142. false        value        bugtest?
  143.  
  144.             variable    ftemp    4 reserve        \ temp area for FP stuff
  145.  
  146. -1            value        modcode_comp_start
  147. -1            value        moddata_comp_start
  148.  
  149. 0            value        compmod        \ addr of module object during compilation
  150.                                     \  of that module, otherwise zero
  151.  
  152. 64            constant    max_segs    \ allows us 31 modules, since each
  153.                                     \ has a code and data segment.
  154.                                     \ Change if necessary.
  155.  
  156.             variable    segTable    max_segs 3 <<  reserve
  157.  
  158.  
  159. forward    DIE            \ ( err# -- )  our normal Mops error handling word
  160. forward RUN            \ ( -- )  starts running after we set everything up
  161. forward ENTERMOD    \ ( xt -- )  in zModules.  Calls a word in a module.
  162. forward .S
  163. forward FIX_CACHES
  164. forward fmrk
  165.  
  166.  
  167. \ : HERE        inline{ DP}  ;
  168.  
  169.  
  170. (*        ====================== Objects, etc. ============================
  171.  
  172.     These are the ones we need for the very early stuff, before our full object
  173.     handling is loaded.  We therefore need to wind them by hand, and in some
  174.     cases patch them later.
  175.  
  176. *)
  177.  
  178.             create        FFCB   8 allot        \ will be an object pointer
  179.  
  180.  
  181.             (createObj) fWind
  182.                 $ 9C    allot
  183.                 8        allot
  184.                 $ 2E    allot
  185.                 
  186.  
  187.             (createObj) fpRect
  188.                 8        allot
  189.             
  190.             (createObj) fEvent
  191.                 18        allot            \ ivars space
  192.                 4  ,                    \ indexed elt width - &&&& changed from 2 to 4 bytes
  193.                 23 ,                    \ #elts - 1
  194.                 24 4*    allot            \ allocate space for them
  195.                 
  196.                         \ ## note we set the offset to the indexed area in file Event
  197.                         \  when we set the class pointer, since that's what we do on
  198.                         \  the 68k and also it's easier to make changes.
  199.  
  200.  
  201. 0            value        InterfaceLib_connID
  202. 0            value        MathLib_connID
  203.  
  204.             variable    vConnID
  205.             variable    mainAddr
  206.             variable    symAddr
  207.             variable    symClass
  208.  
  209. $ 1234 ,
  210.             create        qd        512 allot
  211. $ 4567 ,
  212.                         \ size of QD globals - 206 plus a generous safety
  213.                         \  margin which we seem to need for some unknown
  214.                         \  reason
  215.  
  216.             create        errName        \ can use same space as the following:
  217.  
  218.             create        BUF255        256 allot        \ buffer for string operations
  219.  
  220.  
  221. \ we need these very early:
  222.  
  223. \ $ BD3E 0  special_op        >R
  224. \ $ BD3F 0  special_op        R>
  225.  
  226. \ R@ is defined in cg5 since it's just a base-displ fetch
  227.  
  228.  
  229. \ Currently I'm using locked handles for things like the dictionary
  230. \  area - I could use pointers but using handles allows the possibility
  231. \  of a dynamic size change if we ever want it.
  232.  
  233. : lockedHndl { siz \ hndl addr -- addr }
  234.     siz %_NewHandleClear  -> hndl
  235.     hndl %_MoveHHi
  236.     hndl %_HLock
  237.     hndl @  -> addr
  238.     addr
  239. ;
  240.  
  241. \ inline calls are a bit long-winded, so here we factor out a couple that
  242. \  we need several times:
  243.  
  244. : BYE    %_ExitToShell  ;
  245.  
  246. : call_BlockMove        \ ( src dst len -- )  Just to save some space, since
  247.                         \  inline calls are a bit long-winded.  We use BlockMove
  248.                         \  at this stage rather than BlockMoveData, since we 
  249.                         \  might be moving code.
  250.     %_BlockMove  ;
  251.  
  252.  
  253. : BEEP
  254.     %_SysBeep  ;
  255.  
  256.  
  257. : ?startUpError    \ ( err# -- )
  258.     dup
  259.     IF  3 beep
  260.         bye
  261.     ELSE
  262.         drop
  263.     THEN  ;
  264.  
  265. : ?symbolError    \ ( err# -- )
  266.     ?dup  0EXIT
  267.     -> system_err#  213 die  ;
  268.  
  269.  
  270. : SWITCH_ME  { entPt addr -- }
  271.     lr>treg                    \ gets the return addr to treg
  272.     treg entPt -            \ offset of RA in code block
  273.     addr +                    \ equivalent RA in new code block
  274.     -> treg  treg>lr
  275. ;
  276.  
  277.  
  278. \ @ABS and EXECUTE have to come here, since they're invoked by executing
  279. \  a vector, which we need in SETUP.
  280.  
  281.  
  282. : (@ABS)  { addr \ relocAddr seg# baseAddr displ ^ST -- absAddr | -- 0 }
  283.     addr @  -> relocAddr
  284.     relocAddr  $ ffffff and  -> displ
  285.     relocAddr  24 >>  dup -> seg#  
  286.     dup 1 and NIF -> last_RP_seg# ELSE drop THEN
  287.  
  288.     seg# 8 <  seg#  max_segs 8 + >=  or
  289.     IF    0  EXIT  THEN
  290.     
  291.     seg# 8 -  8 *  segTable +  -> ^ST
  292.                                 \ get addr of the seg table entry we want
  293.  
  294. \ OK so far - now we check if the displ is within the segment
  295. \  this check will also trap an unallocated segment which will
  296. \  have zero length.
  297.  
  298.     displ  ^ST @ $ 00ffffff and  u>=  IF  0 EXIT  THEN
  299.                                             \ err if displ out of bounds
  300.     ^ST 4+ @ -> baseAddr
  301.     baseAddr nilP = IF  206 die  THEN        \ internal error if seg absent
  302.     baseAddr displ +
  303. ;
  304.  
  305. : @ABS  ( ^relocAddr -- absAddr )
  306.     (@abs)  dup ?EXIT
  307.     drop  70 die        \ "not a reloc addr"
  308. ;
  309.  
  310.  
  311. (*    For EXECUTE, we have to resort to assembly since we have to get the right
  312.     number of stack cells into regs as required by the defn we're calling, and
  313.     ditto for the returned results.
  314.     
  315.     On entry, r4 (TOS) = cfa of defn.  This is the addr of the flag bytes.
  316.     The actual code starts 2 bytes later.
  317.     
  318.     Note all assemby defns are assumed to have r4 = TOS and r3 = second,
  319.     on both entry and exit.  We override this in EXECUTE - see the comment there.
  320. *)
  321.  
  322. forward execErr
  323.  
  324.  
  325. :ppc_code PUSHES
  326.     r10        -32    rSP        stw,
  327.     r9        -28 rSP        stw,
  328.     r8        -24 rSP        stw,
  329.     r7        -20 rSP        stw,
  330.     r6        -16 rSP        stw,
  331.     r5        -12 rSP        stw,
  332.     r4        -8    rSP        stw,
  333.     r3        -4    rSP        stw,
  334.                     blr,
  335. ;ppc_code
  336.  
  337.  
  338. :ppc_code PULLS
  339.     r10        4    rSP        lwzu,
  340.     r9        4    rSP        lwzu,
  341.     r8        4    rSP        lwzu,
  342.     r7        4    rSP        lwzu,
  343.     r6        4    rSP        lwzu,
  344.     r5        4    rSP        lwzu,
  345.     r4        4    rSP        lwzu,
  346.     r3        4    rSP        lwzu,
  347.                         blr,
  348. ;ppc_code
  349.  
  350.  
  351. :ppc_code FPUSHES
  352.     fr8        -64    rFSP    stfd,
  353.     fr7        -56 rFSP    stfd,
  354.     fr6        -48 rFSP    stfd,
  355.     fr5        -40 rFSP    stfd,
  356.     fr4        -32 rFSP    stfd,
  357.     fr3        -24 rFSP    stfd,
  358.     fr2        -16    rFSP    stfd,
  359.     fr1        -8    rFSP    stfd,
  360.                         blr,
  361. ;ppc_code
  362.  
  363.  
  364. :ppc_code FPULLS
  365.     fr10    8    rFSP    lfdu,
  366.     fr9        8    rFSP    lfdu,
  367.     fr8        8    rFSP    lfdu,
  368.     fr7        8    rFSP    lfdu,
  369.     fr6        8    rFSP    lfdu,
  370.     fr5        8    rFSP    lfdu,
  371.     fr4        8    rFSP    lfdu,
  372.     fr3        8    rFSP    lfdu,
  373.     fr2        8    rFSP    lfdu,
  374.     fr1        8    rFSP    lfdu,
  375.                         blr,
  376. ;ppc_code
  377.  
  378.  
  379. :ppc_code PULLPARMS
  380.     r24        4    rSP        lwzu,
  381.     r25        4    rSP        lwzu,
  382.     r26        4    rSP        lwzu,
  383.     r27        4    rSP        lwzu,
  384.     r28        4    rSP        lwzu,
  385.     r29        4    rSP        lwzu,
  386.     r30        4    rSP        lwzu,
  387.     r31        4    rSP        lwzu,
  388.                         blr,
  389. ;ppc_code
  390.  
  391.  
  392. :ppc_code FPULLPARMS
  393.     fr24    8    rFSP    lfdu,
  394.     fr25    8    rFSP    lfdu,
  395.     fr26    8    rFSP    lfdu,
  396.     fr27    8    rFSP    lfdu,
  397.     fr28    8    rFSP    lfdu,
  398.     fr29    8    rFSP    lfdu,
  399.     fr30    8    rFSP    lfdu,
  400.     fr31    8    rFSP    lfdu,
  401.                         blr,
  402. ;ppc_code
  403.  
  404.  
  405. :ppc_code SAVES
  406.     r21        -44    rRP        stw,
  407.     r22        -40    rRP        stw,
  408.     r23        -36    rRP        stw,
  409.     r24        -32    rRP        stw,
  410.     r25        -28    rRP        stw,
  411.     r26        -24    rRP        stw,
  412.     r27        -20    rRP        stw,
  413.     r28        -16    rRP        stw,
  414.     r29        -12    rRP        stw,
  415.     r30        -8    rRP        stw,
  416.     r31        -4    rRP        stw,
  417.                         blr,
  418. ;ppc_code
  419.  
  420.  
  421. :ppc_code RESTORES
  422.     r21        -44    rRP        lwz,
  423.     r22        -40    rRP        lwz,
  424.     r23        -36    rRP        lwz,
  425.     r24        -32    rRP        lwz,
  426.     r25        -28    rRP        lwz,
  427.     r26        -24    rRP        lwz,
  428.     r27        -20    rRP        lwz,
  429.     r28        -16    rRP        lwz,
  430.     r29        -12    rRP        lwz,
  431.     r30        -8    rRP        lwz,
  432.     r31        -4    rRP        lwz,
  433.                         blr,
  434. ;ppc_code
  435.  
  436.  
  437. :ppc_code FSAVES
  438.     fr21    -88    rRP        stfd,
  439.     fr22    -80    rRP        stfd,
  440.     fr23    -72    rRP        stfd,
  441.     fr24    -64    rRP        stfd,
  442.     fr25    -56 rRP        stfd,
  443.     fr26    -48 rRP        stfd,
  444.     fr27    -40 rRP        stfd,
  445.     fr28    -32 rRP        stfd,
  446.     fr29    -24 rRP        stfd,
  447.     fr30    -16    rRP        stfd,
  448.     fr31    -8    rRP        stfd,
  449.                         blr,
  450. ;ppc_code
  451.  
  452.  
  453. :ppc_code FRESTORES
  454.     fr21    -88    rRP        lfd,
  455.     fr22    -80    rRP        lfd,
  456.     fr23    -72    rRP        lfd,
  457.     fr24    -64    rRP        lfd,
  458.     fr25    -56 rRP        lfd,
  459.     fr26    -48 rRP        lfd,
  460.     fr27    -40 rRP        lfd,
  461.     fr28    -32 rRP        lfd,
  462.     fr29    -24 rRP        lfd,
  463.     fr30    -16    rRP        lfd,
  464.     fr31    -8    rRP        lfd,
  465.                         blr,
  466. ;ppc_code
  467.  
  468.  
  469.  
  470. :ppc_code (EX)        \ called from EXECUTE, once we've handled a possible
  471.                     \  indirection via a vector.
  472.  
  473. \ in a code defn we always have 2 stack cells and 2 floating stack cells in regs on
  474. \  entry.  So here we have r4 = xt to execute, r3 = next cell down.  We can scribble 
  475. \  on r5-10 until we get the parms into regs.
  476.  
  477. \ If this is a method, the obj addr will be rY (r12), so we have to leave
  478. \  that alone for the first part.
  479.  
  480.     r0                        mflr,        \ save lr on return stack
  481.     r0        -8    rRP            stwu,
  482.  
  483.     fr2        -16    rFSP        stfd,        \ push of fr1 and fr2 - all FP stk cells now in mem
  484.     fr1        -8    rFSP        stfd,
  485.     rFSP    -24                addi,        \ leave rFSP 8 bytes lower than usual, to simplify
  486.                                         \  what follows
  487.  
  488.     rX        r4                mr,            \ rX = addr of flag bytes of defn we're executing
  489.     r5        -2    rX            lhz,        \ r5 = handler code, which we now check
  490.     r0        r5     $ FF00        andi.,        \ BExx is OK
  491.     r0        $ BE00            cmpli,
  492.  
  493. ne if,
  494.     r0        $ BD00            cmpli,
  495.  eq if,
  496.     r6        rX                lhz,        \ OK - there'll be boilerplate code after
  497.      r6        r6    $ FF        andi.,        \  the info bytes.  r6 = # info bytes
  498.      rX        rX    r6            add,        \ add to addr in rX.  Now we need to add 2 for
  499.                                          \ the extra info mark and len, then off-align (by
  500.                                          \ adding 5, 4-byte aligning, then subtracting 2)
  501.      rX        rX    7            addi,        \ so we combine the 5 and 2 and add 7
  502.     rX        rX 0 0 29        rlwinm,        \ back to 4-byte boundary
  503.      rX        rX    -2            addi,        \ now rX -> flag bytes for boilerplate code
  504.  else,
  505.     r0        ' execErr 2+    dicaddr,
  506.     r0                        mtctr,
  507.                             bctr,
  508.  then,
  509. then,
  510.  
  511. \ now we get the flag bytes to r6, and the FP flag bytes to r7.
  512.  
  513.     r6        0    rX            lhz,        \ r6 = flag bytes
  514.  
  515.     r3        -4    rSP            stw,        \ push off r3 - all stk cells are now in mem
  516.     rSP        -8                addi,        \ leave rSP 4 bytes lower than usual, to simplify
  517.                                         \  what follows
  518.                                         
  519.     r0        r6    $ 1000        andi.,        \ look at "fp" bit in flags
  520.  ne if,
  521.       r7    4    rX            lhz,        \ if set, get FP flag bytes to r7
  522.  else,
  523.        r7    $ 0200            li,            \ otherwise put default flag bytes there
  524.  then,
  525.  
  526.     r0        r6    $ 8000        andi.,        \ look at "leaf" bit in flags
  527.     
  528. ne if,
  529. \ it's a leaf routine.  We do the work of the prolog and epilog here rather than in
  530. \  the called routine.  r3 is unused here so we can use it.
  531.  
  532. \ First we save the FPRs, since we know RP is 8-byte aligned:
  533.  
  534.     r3        r7 2 26 29        rlwinm,        \ r3 = # FP parm+locals, times 4
  535.     r0        ' fsaves 46 +    dicaddr,    \ addr of end of "fsaves" code to r0
  536.     r0        r3 r0            subf,        \ subtract offset
  537.     r0                        mtctr,
  538.                             bctrl,        \ save the required FP regs
  539.     r0        r3    r3            add,        \ double offset for rRP decrement
  540.     rRP        r0    rRP            subf,        \ decrement rRP over saved FPRs
  541.  
  542. \ Now we save the GPRs:
  543.  
  544.     r3        r6 2 26 29        rlwinm,        \ r3 = # parms+locals, times 4
  545.     r0        ' saves 46 +    dicaddr,    \ addr of end of "saves" code to r0
  546.     r0        r3 r0            subf,        \ subtract offset
  547.     r0                        mtctr,
  548.                             bctrl,        \ save the required regs
  549.     rRP        r3    rRP            subf,        \ decrement rRP over saved regs
  550.  
  551.  
  552.     r0        r5    $ FF        andi.,
  553.     r0        $ 40            cmpli,        \ method?
  554.  eq if,
  555.     r20        -4    rRP            stwu,        \ yes - save r20
  556.     r20        rY                mr,            \ and move rY to there
  557.  then,
  558.  
  559. \ now we look after the parms themselves - we set up for them to go straight to
  560. \  their ultimate destination regs.  First any FP parms:
  561.  
  562.     r3        r7 30 26 29        rlwinm,        \ r3 = # FP parms, times 4
  563.     r0    ' fpullParms 34 +    dicaddr,    \ addr of end of "pullParms" code to r0
  564.     r0        r3 r0            subf,        \ subtract offset
  565.     r0                        mtctr,
  566.                             bctrl,        \ pull the FP parms we need into regs up to fr31
  567.  
  568. \ now we look after any FP stack cells that have to go to regs - this will only
  569. \  happen if our default call_cnt (2) is greater than the number of named parms.
  570. \ Note the most pulls we'll do is to fr1 and fr2.
  571.  
  572.     r0        8                li,
  573.     r3        r3    r0            subf.,        \ r3 = 8 - ( # FP parms * 4 )
  574.  gt if,
  575.     r0        ' fpulls 42 +    dicaddr,    \ addr of end of "pulls" code to r0
  576.     r0        r3 r0            subf,        \ subtract offset
  577.     r0                        mtctr,
  578.                             bctrl,        \ pull the floating stack cells we need into regs
  579.  then,
  580.  
  581.     r3        r6 30 26 29        rlwinm,        \ r3 = # parm bytes
  582.     r0    ' pullParms 34 +    dicaddr,    \ addr of end of "pullParms" code to r0
  583.     r0        r3 r0            subf,        \ subtract offset
  584.     r0                        mtctr,
  585.                             bctrl,        \ pull the parms we need into regs up to r31
  586.     
  587. \ now we look after any stack cells that have to go to regs - this will only
  588. \  happen if our default call_cnt (2) is greater than the number of named parms.
  589. \ Note the most pulls we'll do is to r3 and r4, so r5-7 will be untouched.
  590.  
  591.     r0        8                li,
  592.     r3        r3    r0            subf.,        \ r3 = 8 - # parm bytes
  593.  gt if,
  594.     r0        ' pulls 34 +    dicaddr,    \ addr of end of "pulls" code to r0
  595.     r0        r3 r0            subf,        \ subtract offset
  596.     r0                        mtctr,
  597.                             bctrl,        \ pull the stack cells we need into regs
  598.  then,
  599.  
  600. \ before we call the routine we save the flag bytes, the handler code and rX,
  601. \  since we need them later.  In this leaf handling code we have to do this
  602. \  last since we've saved regs for the callee, and we'll need to restore
  603. \  these quantities first.
  604.  
  605.     r5        -4    rRP            stwu,
  606.     r6        -4    rRP            stwu,
  607.     rX        -4    rRP            stwu,
  608.  
  609. else,
  610. \  not a leaf routine.
  611.  
  612. \ first we save the same quantities as above - but here we have to do it first,
  613. \  since we might be clobbering r5/r6 if the callee needs them.
  614.  
  615.     r5        -4    rRP            stwu,
  616.     r6        -4    rRP            stwu,
  617.     rX        -4    rRP            stwu,
  618.  
  619.     r3        r7 30 26 29        rlwinm,        \ r3 = # fp parms, times 4
  620.     r0        8                li,
  621.     r3        r0                cmp,
  622.  lt if,
  623.       r3    r0                mr,            \ if < 8, make it 8 since that's our minimum
  624.  then,
  625.     
  626.     r0        ' fpulls 42 +    dicaddr,    \ addr of end of "fpulls" code to r0
  627.     r0        r3 r0            subf,        \ subtract offset
  628.     r0                        mtctr,
  629.                             bctrl,        \ pull the fp cells we need into fp regs
  630.  
  631.     r3        r6 30 26 29    rlwinm,            \ r3 = # parms, times 4
  632.     r0        8                li,
  633.     r3        r0                cmp,
  634.  lt if,
  635.       r3    r0                mr,            \ if < 8, make it 8 since that's our minimum
  636.  then,
  637.     
  638.     r0        ' pulls 34 +    dicaddr,    \ addr of end of "pulls" code to r0
  639.     r0        r3 r0            subf,        \ subtract offset
  640.     r0                        mtctr,
  641.                             bctrl,        \ pull the cells we need into regs
  642.  
  643. then,
  644.  
  645.     rSP        4                addi,        \ stack ptrs back to normal
  646.     rFSP    8                addi,
  647.  
  648. \ now we have to 8-byte align the RP since anything might happen in the callee.
  649. \ If we have to do it we'll push a 4-byte zero.  Since rX, the last reg we saved
  650. \  there, can never be zero, this lets us sorts things out when the callee returns.
  651.  
  652.     r0        rRP    7            andi.,
  653. ne if,
  654.     r0        0                li,
  655.     r0        -4    rRP            stwu,
  656. then,
  657.  
  658. \ now we're going to call the routine - first we need the address of its
  659. \  first instruction.
  660.  
  661.     r0        r6    $ 1000        andi.,        \ look at "fp" bit in flags
  662. ne if,
  663.     r0        rX    6            addi,
  664. else,
  665.     r0        rX    2            addi,        \ addr of code to r0
  666. then,
  667.  
  668.     r0                        mtctr,
  669.  
  670. \ **************************************************************************
  671.                             bctrl,        \ call it
  672. \ **************************************************************************
  673.  
  674. \ At this point we have to allow for the maximum number of live values
  675. \  in GPRs, which is 6.  This means r9 will always be free here,
  676. \  and we can also use r0, rX, rY and rZ (aka r10).
  677.  
  678.     rX        0    rRP            lwz,        \ restore rX
  679.     rX        0                cmpi,
  680. eq if,                                    \ but if we got zero, it was alignment
  681.     rRP        4                addi,        \  padding, so we skip it and try again
  682.     rX        0    rRP            lwz,        \ restore rX
  683. then,
  684.     r10        4    rRP            lwz,        \ restore flag bytes, into r10 this time
  685.     r9        8    rRP            lwz,        \ restore handler code to r9
  686.     rRP        12                addi,
  687.  
  688. \ all we need from the handler code is whether this is a method or not, so
  689. \  we'll get this to cr1, then we can reuse r9.
  690.  
  691.     r0        r9    $ FF        andi.,
  692.     cr1        r0    $ 40        cmpli,        \ cr1 is "equal" if it's a method
  693.  
  694.     r0        r10    $ 1000        andi.,        \ look at "fp" bit in flags
  695.  ne if,
  696.       r9    4    rX            lhz,        \ if set, get FP flag bytes to r9
  697.  else,
  698.        r9    $ 0200            li,            \ otherwise put default flag bytes there
  699.  then,
  700.  
  701.     r0        r10    $ 8000        andi.,        \ test "leaf" bit in flags
  702. ne if,
  703. \ it was a leaf routine.
  704.  
  705.  cr1 eq if,                                \ method?
  706.     r20        rRP                lwz,        \ yes - restore r20
  707.     rRP        4                addi,
  708.  then,
  709.  
  710.     rY        r10 2 26 29        rlwinm,        \ rY = # parms+locals, times 4
  711.     r0        ' restores 46 +    dicaddr,    \ addr of end of "restores" code to r0
  712.     r0        rY r0            subf,        \ subtract offset
  713.     rRP        rRP    rY            add,        \ increment rRP over saved GPRs
  714.     r0                        mtctr,
  715.                             bctrl,        \ restore the saved regs
  716.  
  717.     rY        r9 2 26 29        rlwinm,        \ rY = # FP parm+locals, times 4
  718.     r0    ' frestores 46 +    dicaddr,    \ addr of end of "frestores" code to r0
  719.     r0        rY r0            subf,        \ subtract offset
  720.     rRP        rY                add,        \ increment rRP over saved FPRs (8 bytes
  721.     rRP        rY                add,        \  each)
  722.     r0                        mtctr,
  723.                             bctrl,        \ restore the saved FPRs    
  724. then,
  725.  
  726. \ now we push off all result regs to mem - we return 2 in GPRs and 2 in FPRs
  727. \ from here, but it's easiest to grab those back after the pushes.
  728.  
  729.     rY        r10 26 26 29    rlwinm,        \ rY = # result regs, times 4
  730.     r0        ' pushes 34 +    dicaddr,    \ addr of end of "pushes" code to r0
  731.     r0        rY    r0            subf,        \ subtract offset
  732.     r0                        mtctr,
  733.                             bctrl,        \ push all result regs to mem
  734.     rSP        rY rSP            subf,        \ adjust stack ptr
  735.  
  736.      rY        r9 26 26 29        rlwinm,        \ rY = # FP result regs, times 4
  737.     r0        ' fpushes 34 +    dicaddr,    \ addr of end of "fpushes" code to r0
  738.     r0        rY    r0            subf,        \ subtract offset
  739.     r0                        mtctr,
  740.                             bctrl,        \ push all result regs to mem
  741.     rY        rY                add,
  742.     rFSP    rY rFSP            subf,        \ adjust stack ptr
  743.  
  744.  
  745.     r4        0    rSP            lwz,
  746.     r3        4    rSP            lwz,
  747.     rSP        8                addi,
  748.     
  749.     fr2        0    rFSP        lfd,
  750.     fr1        8    rFSP        lfd,
  751.     rFSP    16                addi,
  752.  
  753.     r0        0    rRP            lwz,
  754.     rRP     8                addi,
  755.     r0                        mtlr,        \ restore lr
  756.                             blr,        \ and return.
  757. ;ppc_code        uses_ctr
  758.  
  759.  
  760. : EXECUTE  ( xt -- ?? )
  761.     dup 2- w@ $ BC41 =
  762.     IF                            \ it's a MARKER
  763.         2+ fmrk  EXIT
  764.     THEN
  765.  
  766.     dup 2- w@ $ BC0C =
  767.     IF                            \ it's a DOES> word
  768.         dup 2+ @abs                \ get addr of CREATEd data
  769.         swap 6 + @abs            \ and xt of DOES> code
  770.     ELSE
  771.         BEGIN
  772.             dup 2- w@ $ BC05 =
  773.         WHILE                    \ it's a vector
  774.             2+ @abs                \ goto data area
  775.             @abs                \ pick up dest xt
  776.         REPEAT                    \ and loop in case we get another vector
  777.     
  778.         dup 2- w@ $ BD2E =
  779.         IF                        \ it's an exported word
  780.             ['] enterMod        \ for these we execute enterMod which
  781.         THEN                    \  does the work
  782.     THEN
  783.  
  784.     (ex)            \ (ex) does the actual work of executing the word
  785. ;
  786.  
  787.  
  788. : DoVect
  789.     @abs execute  ;
  790.  
  791. : DoSvect
  792.     dup @ NIF  4+  THEN
  793.     @abs execute  ;
  794.  
  795. : ^THEPORT  ( -- addr )
  796.     inline{ qd 256 +}  ;        \ should theoretically only be 110, but we
  797.                                 \  seem to need more - see comment at qd
  798.  
  799. : THEPORT  ( -- addr-of-GrafPort )
  800.     inline{ qd 256 + @}  ;
  801.  
  802.  
  803. : SCREENBITS  { \ ^rect -- l t r b }
  804.     qd  $ 8c +  -> ^rect
  805.     ^rect 2+  w@  ^rect    w@
  806.     ^rect 6 + w@  ^rect 4+ w@
  807. ;
  808.  
  809.  
  810. (*    SAVE_MOPS_REGS saves the Mops base address regs and stack pointers
  811.     into the TOC area.  We need these saved values for callbacks, and
  812.     also if if we're a shared library - in these situations we have
  813.     to restore the Mops environment before we can do anything else.
  814.     These saved values come at the end of our TOC.  TOC_size is currently
  815.     132.  If it changes, we'll have to change the numbers here, and
  816.     in get_transition_vector below, and    also in :ppc_proc and ;ppc_proc
  817.     in zObjinit.
  818. *)
  819.  
  820.  
  821. :ppc_code SAVE_MOPS_REGS
  822.     r13        104    rTOC    stw,
  823.     r14        108    rTOC    stw,
  824.     r15        112    rTOC    stw,
  825.     r16        116    rTOC    stw,
  826.     r17        120    rTOC    stw,
  827.     r18        124    rTOC    stw,
  828.     r19        128    rTOC    stw,
  829.                         blr,
  830. ;ppc_code
  831.  
  832.  
  833. \ we call PREPARE_SYSCALLS at startup time to get the shared libraries
  834. \  we need.  Currently, these are InterfaceLib and MathLib.
  835.  
  836. : get_shared_library  { addr -- connID true  | -- false }
  837.     addr                        \ addr is pascal string
  838.     'type pwpc                    \ PowerPC library
  839.     1                            \ load the library if not loaded
  840.     vConnID
  841.     mainAddr
  842.     errName
  843.     %_GetSharedLibrary  ?dup
  844.     IF  -> system_err#  false  EXIT  THEN
  845.     vConnID @  true
  846. ;
  847.  
  848.  
  849. : get_connID  { ^extern \ ^lib ^connID -- connID }
  850.             \ gets the connID for an arbitrary shared library
  851.     ^extern 10 + @abs  -> ^lib
  852.     ^lib 2+ @abs  -> ^connID
  853.     ^connID @  ?dup ?EXIT
  854.  
  855. \ not connected yet - we do it now
  856.     ^lib  6 +  get_shared_library
  857.     NIF  220 die  THEN            \ could not load shared library
  858.     dup  ^connID !
  859. ;
  860.  
  861.  
  862. : PREPARE_SYSCALLS  ( -- )
  863.     " InterfaceLib" drop 1-
  864.     get_shared_library  not ?startUpError
  865.     -> InterfaceLib_connID
  866.  
  867.     " MathLib" drop 1-
  868.     get_shared_library  not ?startUpError
  869.     -> MathLib_connID
  870. ;
  871.  
  872. 0 value tvtest
  873. : get_transition_vector  { ^extern \ extern? ^tv connID -- }
  874.  
  875.     ^extern 10 + @
  876.     IF        \ this is a LIBCALL.  We look in the given library.
  877.         ^extern get_connID
  878.     ELSE    \ it's a syscall.  We look in InterfaceLib and MathLib.
  879.         InterfaceLib_connID
  880.     THEN  -> connID
  881.  
  882.     ^extern 6 + @abs  -> ^tv
  883.     ^tv @  nilP =
  884.     IF            \ hasn't been called yet - we resolve it now
  885.         connID  
  886.         ^extern 14 +            \ addr of symbol (Pascal string)
  887.         ^tv                        \ addr of location where resolved pointer will go
  888.         symClass
  889.         %_FindSymbol
  890.         IF                \ didn't find it there - try in MathLib
  891.             MathLib_connID
  892.             ^extern 14 +        \ addr of symbol (Pascal string)
  893.             ^tv                    \ addr of location where resolved pointer will go
  894.             symClass
  895.             %_FindSymbol
  896.             ?symbolError        \ if we still didn't find it, fail
  897.         THEN
  898.     THEN
  899. tvtest if dbgr then
  900.     modcode  rTOC 112 + !        \ set global copies of module base regs
  901.     moddata  rTOC 116 + !        \  in case there's a callback
  902.     
  903.     ^tv @  -> rY                \ r12 -> transition vector
  904.     [    $ 800C0000 code,        \ lwz  r0, (r12) - get dest addr to r0
  905.         $ 7C0903A6 code,        \ mtctr r0         - and then to ctr
  906.     ]
  907. ;
  908.  
  909.  
  910. : SETUP  { \ hndl addr entPt codeSz dataSz cg_code cg_data
  911.                 total_code total_data flags chopped -- }
  912.  
  913.     initial_entry_point
  914.     fix_sys_SP
  915.  
  916. \ First we grow the application heap:
  917.     %_MaxApplZone
  918.  
  919. \ now we allocate a block for the return stack:
  920.     rstack_size %_NewHandleClear  -> hndl
  921.     hndl %_MoveHHi
  922.     hndl %_HLock
  923.     hndl @  -> addr
  924.     addr rstack_size +  -> RP        \ RP is set up - now we can do calls!
  925.  
  926.     $ CD  $ AB                        \ leave markers on the stack - these might also
  927.                                     \  hopefully catch a stack underflow
  928.  
  929.     $ CDCD >r  $ ABAB >r            \ and also on the return stack
  930.  
  931. \ now we grab the items we need out of the info block
  932. \  at the start of the code area
  933.  
  934.     entry_point_toc_offset  RTOC + @  -> entPt
  935.     entPt 4 + @        -> codeSz
  936.     entPt 8 + @        -> dataSz
  937.     entPt 12 + @    -> cg_code
  938.     entPt 16 + @    -> cg_data
  939.     entPt 52 + @    -> flags
  940.  
  941. \ now we set up the base regs and the segment table so we can
  942. \  address things.  First the data area:
  943.  
  944.     flags 1 and
  945.     IF            \ this is an installed app.
  946.         dataSz -> total_data
  947.         RTOC -> addr
  948.     ELSE        \ we're in the development environment, so the data
  949.                 \  area goes in a handle:
  950.         entPt 68 + @  -> total_data
  951.         total_data  lockedHndl  -> addr
  952.         RTOC  addr  dataSz  call_BlockMove
  953.     THEN
  954.  
  955.     addr cg_data + half_displ_range +  -> mainData
  956.     -1 -> modData
  957.  
  958. \ with the data area set up, we can now store to it!
  959.  
  960.     total_data dataSz -  -> spare_data_size
  961.  
  962.     entPt 60 + @  -> chopped
  963.     total_data  chopped +    segTable  8 + !
  964.     addr  chopped -            segTable 12 + !
  965.  
  966.     addr -> data_start
  967.     addr cg_data +  -> nuc_data_start
  968.     addr total_data +  -> data_limit
  969.     addr dataSz +  -> DP
  970.  
  971. \ now the code area
  972.  
  973.     flags 1 and
  974.     IF            \ this is an installed app.
  975. \        true -> instld?                \ in case it wasn't set already
  976.         codeSz -> total_code
  977.         entPt -> addr
  978.     ELSE
  979.         entPt 64 + @  -> total_code
  980.         total_code  lockedHndl  -> addr
  981.         entPt  addr  codeSz  call_BlockMove
  982.     THEN
  983.  
  984.     addr cg_code + half_displ_range +  -> mainCode
  985.     -1 -> modCode
  986.  
  987.     total_code codeSz -  -> spare_code_size
  988.  
  989.     entPt 56 + @  -> chopped
  990.     total_code  chopped +    segTable !
  991.     addr  chopped -            segTable 4+ !
  992.  
  993.     addr -> code_start
  994.     addr cg_code +  -> nuc_code_start
  995.     addr total_code +  -> code_limit
  996.     addr codeSz +  dup -> CDP -> prev_CDP
  997.  
  998.     addr 20 +  -> context
  999.     
  1000.     flags 1 and
  1001.     NIF            \ development
  1002.  
  1003.         addr codeSz  %_MakeDataExecutable
  1004.  
  1005. \ now the interesting bit - we switch execution into the handle
  1006. \  where we just moved the code!
  1007.         entPt  addr  switch_me
  1008.     THEN
  1009.  
  1010. \ now the FP stack area:
  1011.     fstack_size 20 +  lockedHndl
  1012.     fstack_size +  -> FSP
  1013.  
  1014. \ now set up the values with the base addrs of the 3 stacks:
  1015.  
  1016.     SP    -> SP0                \ no cells in regs just here, as it turns out
  1017.     RP    -> RP0
  1018.     -1 -> (^base)            \ no current object
  1019.  
  1020.     $ 7ff86400    ftemp !        \ quiet NAN(100)
  1021.  
  1022.     ftemp sf@  ftemp sf@    \ put 4 of them at base of FP stack
  1023.     ftemp sf@  ftemp sf@
  1024.     
  1025.     0 ftemp !  ftemp f@ -> 0.0        \ initialize fpr14 to zero (we use it
  1026.                                     \  as a permanent source of zero)    
  1027.  
  1028. (*    Now we init the managers.
  1029.  
  1030.     Note: it seems, for some reason, that if we call InitGraf in a shared 
  1031.     library at init time, we crash the calling application when it
  1032.     next calls QD.  Maybe QD doesn't like multiple InitGrafs within 
  1033.     the one thread, even though we're using separate copies of the QD 
  1034.     globals.  Anyway, for now, let's skip the InitGraf if this is a shared 
  1035.     library.
  1036. *)
  1037.     flags 2 and
  1038.     nif
  1039.         ^thePort %_InitGraf    \ note: what we have to pass to InitGraf is the
  1040.                             \  addr of thePort which is a pointer near the END
  1041.                             \  of the QD globals record!
  1042.         %_InitFonts
  1043.         %_InitWindows
  1044.         %_TeInit
  1045.         %_InitMenus
  1046.         %_InitCursor
  1047.     then
  1048.  
  1049.     FSP 48 - -> FSP0        \ The external calls have pushed all our dummy FP
  1050.                             \  cells into mem at this point
  1051.  
  1052. \ now we allocate a block for fFcb, TIB, PAD and the error dump area, and
  1053. \  set up fFcb (which is an object pointer) pointing there.  fFcb will be set up
  1054. \  properly when Files is loaded.
  1055.  
  1056.     FBlkLen 10 +  lockedHndl  -> addr    \ the 10 is just a safety margin
  1057.     8 ++> addr                            \ leave room for obj header
  1058.     addr  ffcb !
  1059.     FCBlen ++> addr        addr -> pad
  1060.     PADlen ++> addr        addr -> TIB
  1061.     TIBlen ++> addr        addr -> ^errDump
  1062.  
  1063. \ Noe we get the shared lib for system calls.  After this we can
  1064. \  execute syscall words.
  1065.  
  1066.     prepare_syscalls
  1067.  
  1068.     %_NewRgn  -> theRgn
  1069.  
  1070. \ now if needed, we get our low-level window fWind.
  1071.  
  1072.     fWind?
  1073.     IF    256                \ resID
  1074.         fWind
  1075.         -1
  1076.         %_GetNewWindow
  1077.         %_SetPort
  1078.         fWind -> addr
  1079.         9  addr 74 +  w!            \ point size = 9
  1080.         4  addr 68 +  w!            \ font = Monaco
  1081.     
  1082.         addr 16 + @  addr 156 + !    \ set fWind's contRect in case not done
  1083.         addr 20 + @  addr 160 + !
  1084.  
  1085.         addr 16 + @  fpRect !        \ set fpRect (used for scrolling)
  1086.         addr 20 + @  fpRect 4 + !
  1087.  
  1088. \        %_NewRgn  -> theRgn
  1089.         0   %_TextMode
  1090.         
  1091.         true -> emit?
  1092.     THEN
  1093.  
  1094.     objInit
  1095.  
  1096. \ now we save a copy of the Mops base regs and stack pointers 
  1097. \  in the TOC, for :ppc_proc and :entry
  1098.  
  1099.     save_Mops_regs
  1100.  
  1101.     flags 2 and            \ is this a shared library initialization call?
  1102.     IF                    \ yes - restore everything and return to caller
  1103.         init_end
  1104.     ELSE                \ no - start normal Mops execution
  1105.         run
  1106.         %_ExitToShell
  1107.     THEN
  1108. ;
  1109.